const { browser } = require('webextension-polyfill-ts');


/**
 * el -> original rect
 * @type {Map<HTMLElement, {observer: NodeJS.Timer, orig_rect: DOMRect}>}
 */
let mirroring_els = new Map();

/**
 * @param {HTMLElement} el
 */
async function stop_mirroring_element(el) {
  if (!mirroring_els.has(el))
    return;
  /**
   * NOTE: currently one tab can only mirror one element
   */
  stop_all_mirroring_elements();
}

async function stop_all_mirroring_elements() {
  await browser.runtime.sendMessage({op: 'StopMirroringTab'});
  for (let {observer, _} of mirroring_els.values())
    clearInterval(observer);
  mirroring_els.clear();
}


/**
 * Init process
 */
(async () => {
  await browser.runtime.sendMessage({op: 'noop'});

  browser.runtime.onMessage.addListener(async (msg, sndr) => {
    console.debug(`received message: ${JSON.stringify(msg)}`);
    if (msg.op === 'noop')
      return;

    if (msg.op === 'ToggleMirroringElement') {
      if (mirroring_els.size) {
        stop_all_mirroring_elements();
        return;
      }
      const el = document.querySelector('video');
      /* check if element is valid */
      if (el === null) {
        // TODO: user friendly alert
        throw new Error('no <video> element found on this page');
      }
      /* check if element size fit in capturable area */
      const doc_metrics = {
        height: document.documentElement.clientHeight,
        width: document.documentElement.clientWidth
      };
      const el_metrics = el.getBoundingClientRect();
      if (el_metrics.width >= doc_metrics.width
            || el_metrics.height >= doc_metrics.height) {
        // TODO: user friendly alert
        throw new Error('the screen cannot accomodate the element');
      }
      /* make element visible if not already */
      if (el_metrics.x < 0 || el_metrics.y < 0
          || el_metrics.right > doc_metrics.width || el_metrics.bottom > doc_metrics.height)
        el.scrollIntoView();
      /* create the mirror */
      const orig_rect = el.getBoundingClientRect();
      await browser.runtime.sendMessage({
        op: 'StartMirroringElement',
        /* raw window metrics */
        outer_metrics: {
          height: window.outerHeight,
          width: window.outerWidth
        },
        /* actual window display metrics */
        inner_metrics: {
          height: window.innerHeight,
          width: window.innerWidth
        },
        /* scrollbar/sidebar/DevTool-free metrics */
        doc_metrics: {
          height: document.documentElement.clientHeight,
          width: document.documentElement.clientWidth
        },
        dpi: window.devicePixelRatio,
        el_metrics: orig_rect
      });
      mirroring_els.set(el, {
        orig_rect: orig_rect,
        observer: setInterval(async () => {
          if (JSON.stringify(el.getBoundingClientRect()) !== JSON.stringify(orig_rect)) {
            console.debug('stopping mirror for rect changed');
            await stop_mirroring_element(el);
          }
        }, 500)
      });
      return;
    }

    throw new Error(`unknown message op ${msg.op}`);
  });

})();
